package com.dayuanit.dy15.atm.service.impl;

import com.dayuanit.dy15.atm.dto.CardDTO;
import com.dayuanit.dy15.atm.entity.Card;
import com.dayuanit.dy15.atm.entity.Flow;
import com.dayuanit.dy15.atm.enums.FlowTypeEnum;
import com.dayuanit.dy15.atm.exception.BizException;
import com.dayuanit.dy15.atm.mapper.CardMapper;
import com.dayuanit.dy15.atm.mapper.FlowMapper;
import com.dayuanit.dy15.atm.service.CardService;
import com.dayuanit.dy15.atm.util.CardUtil;
import com.dayuanit.dy15.atm.util.DBUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class CardServiceImpl implements CardService {
    /**
     * 存款类型
     */
    public static final int DEPOSIT_FLOW_TYPE = 1;

    /**
     * 取款类型
     */
    public static final int DRAW_FLOW_TYPE = 2;

    /**
     * 银行卡开户
     * @param password 密码
     * @param confirmPassword 确认密码
     */
    @Override
    public int openaccount(long userId, String password, String confirmPassword) {
        //TODO 参数校验 非空校验
        if (StringUtils.isBlank(password) || StringUtils.isBlank(confirmPassword)) {
            throw new BizException("有必填参数为空");
        }

        //TODO 长度校验 两次密码是否相等  强度的校验
        if (password.length() < 4 || confirmPassword.length() < 4) {
            throw new BizException("密码长度必须大于等于4");
        }

        if (!password.equals(confirmPassword)) {
            throw new BizException("两次密码不相等");
        }

        // 开户 向数据库添加一条记录
        try (SqlSession sqlSession = DBUtils.getSqlSession();) {
            CardMapper mapper = sqlSession.getMapper(CardMapper.class);

            //根据银行卡号查询一下是否重复
            String cardNum = CardUtil.createCardNum();
            Card card = mapper.getCardByNum(cardNum);
            if (null != card) {
                throw new BizException("卡号重复");
            }

            card = new Card();
            card.setBalance(0);
            card.setCardNum(cardNum);
            card.setCreateTime(new Date());
            card.setModifyTime(card.getCreateTime());
            card.setPassword(password);
            card.setStatus(1);
            //当前用户
            card.setUserId(userId);

            int rows = mapper.insert(card);
            if (1 != rows) {
                throw new BizException("开户失败");
            }
            return rows;
        }

    }

    /**
     * 存款
     * @param cardNum 卡号
     * @param password 密码
     * @param amount 存款金额 单位：元
     * @return
     */
    @Override
    public int deposit(Long cardId, String password, String amount) {
        //用户给的参数都是邪恶的
        if (null == cardId
                || StringUtils.isBlank(password)
                || StringUtils.isBlank(amount)) {
            throw new BizException("有必填参数为空");
        }

        SqlSession sqlSession = DBUtils.getSqlSession(false);
        try {
            CardMapper cardMapper = sqlSession.getMapper(CardMapper.class);
            Card card = cardMapper.selectByPrimaryKey(cardId);

            if (null == card) {
                throw new BizException("卡号不存在或者密码错误");
            }

            //校验密码
            if (!password.equals(card.getPassword())) {
                throw new BizException("卡号不存在或者密码错误");
            }

            //校验金额
            if (Double.parseDouble(amount) <= 0) {
                throw new BizException("存款金额必须大于零");
            }

            //加钱
            Integer balance = card.getBalance();
            double doubleAmount = Double.parseDouble(amount);
            balance = (int)(doubleAmount * 100) + balance;
            System.out.println("balance = " + balance);

            card.setBalance(balance);
            System.out.println(card.getBalance());
            int row = cardMapper.updateByPrimaryKey(card);
            if (1 != row) {
                throw new BizException("存款失败");
            }

            // 添加流水
            FlowMapper flowMapper = sqlSession.getMapper(FlowMapper.class);
            Flow flow = new Flow();
            flow.setAmount((int)(Double.parseDouble(amount) * 100));
            flow.setCardId(card.getId());
            flow.setCreateTime(new Date());
            flow.setFlowType(FlowTypeEnum.DEPOSIT.getK());
            flow.setRemark(FlowTypeEnum.DEPOSIT.getV());
            flow.setUserId(card.getUserId());

            row = flowMapper.insert(flow);
            if (1 != row) {
                throw new BizException("存款失败");
            }

            //提交事务
            sqlSession.commit();
        } catch (Exception e) {
            //此处catch异常，是为了回滚事务，但是别忘记，要将异常上报给高层，告诉高层，有异常发生；否则servlet会做出错误的响应给用户。
            //回滚事务
            sqlSession.rollback();

            //将异常上抛，告诉高层，这里发生了异常
            throw e;
        } finally {
            sqlSession.close();
        }

        return 0;
    }

    @Override
    public int withdraw(Long cardId, String password, String amount) {
        if (null == cardId
                || StringUtils.isBlank(password)
                || StringUtils.isBlank(amount)) {
            throw new BizException("有必填参数为空");
        }

        SqlSession sqlSession = DBUtils.getSqlSession(false);
        try {
            CardMapper cardMapper = sqlSession.getMapper(CardMapper.class);
            Card card = cardMapper.selectByPrimaryKey(cardId);

            if (null == card) {
                throw new BizException("卡号不存在或者密码错误");
            }

            //校验密码
            if (!password.equals(card.getPassword())) {
                throw new BizException("卡号不存在或者密码错误");
            }

            //校验金额
            if (Double.parseDouble(amount) <= 0) {
                throw new BizException("存款金额必须大于零");
            }

            //判断余额
            if (card.getBalance() < 100 * (int)Double.parseDouble(amount)) {
                throw new BizException("余额不足，请充值");
            }

            //减钱
            Integer balance = card.getBalance();
            double doubleAmount = Double.parseDouble(amount);
            balance =  balance - (int)(doubleAmount * 100);
            System.out.println("balance = " + balance);

            card.setBalance(balance);

            System.out.println(card.getBalance());

            int row = cardMapper.updateByPrimaryKey(card);
            if (1 != row) {
                throw new BizException("取款失败");
            }

            // 添加流水
            FlowMapper flowMapper = sqlSession.getMapper(FlowMapper.class);
            Flow flow = new Flow();
            flow.setAmount(-(int)(Double.parseDouble(amount) * 100));
            flow.setCardId(card.getId());
            flow.setCreateTime(new Date());
            flow.setFlowType(FlowTypeEnum.DRAW.getK());
            flow.setRemark(FlowTypeEnum.DRAW.getV());
            flow.setUserId(card.getUserId());

            row = flowMapper.insert(flow);
            if (1 != row) {
                throw new BizException("取款失败");
            }

            //提交事务
            sqlSession.commit();
        } catch (Exception e) {
            //此处catch异常，是为了回滚事务，但是别忘记，要将异常上报给高层，告诉高层，有异常发生；否则servlet会做出错误的响应给用户。
            //回滚事务
            sqlSession.rollback();

            //将异常上抛，告诉高层，这里发生了异常
            throw e;
        } finally {
            sqlSession.close();
        }

        return 0;
    }

    /**
     * 转账
     * @param cardNumOut 转出银行卡
     * @param cardNumIn 转入银行卡
     * @param password 转出密码
     * @param amount 转账金额 单位：元
     * @return
     */
    @Override
    public int transfer(Long cardId, String cardNumIn, String password, String amount) {
        //TODO 参数校验
        if (null == cardId
                || StringUtils.isBlank(cardNumIn)
                || StringUtils.isBlank(password)
                || StringUtils.isBlank(amount)) {
            throw new BizException("有必填参数为空");
        }

        //TODO 获取sqlSession 开事务
        SqlSession sqlSession = DBUtils.getSqlSession(false);
        try {
            CardMapper cardMapper = sqlSession.getMapper(CardMapper.class);
            FlowMapper flowMapper = sqlSession.getMapper(FlowMapper.class);

            Card cardOut = cardMapper.selectByPrimaryKey(cardId);
            if (cardOut == null) {
                throw new BizException("转出卡号不存在或者密码错误");
            }

            Card cardIn = cardMapper.getCardByNum(cardNumIn);
            if (null == cardIn) {
                throw new BizException("转入卡号不存在");
            }

            //校验金额
            double doubleAmount = Double.parseDouble(amount);
            if (doubleAmount <= 0) {
                throw new BizException("转账金额必须大于零");
            }

            //校验密码
            if (!password.equals(cardOut.getPassword())) {
                throw new BizException("转出卡号不存在或者密码错误");
            }

            // 转出金额 流水
            int newBalance = cardOut.getBalance() - (int)(doubleAmount * 100);
            if (newBalance < 0) {
                throw new BizException("余额不足，请充值");
            }

            cardOut.setBalance(newBalance);

            int rows = cardMapper.updateByPrimaryKey(cardOut);
            if (1 != rows) {
                throw new BizException("转账失败");
            }

            Flow flow = new Flow();
            flow.setUserId(cardOut.getUserId());
            flow.setRemark(FlowTypeEnum.TRANSFER_OUT.getV());
            flow.setFlowType(FlowTypeEnum.TRANSFER_OUT.getK());
            flow.setCreateTime(new Date());
            flow.setCardId(cardOut.getId());
            flow.setAmount(-(int)(Double.parseDouble(amount) * 100));

            rows = flowMapper.insert(flow);
            if (1 != rows) {
                throw new BizException("转账失败");
            }

            // 转入金额 流水
            newBalance = cardIn.getBalance() + (int)(doubleAmount * 100);
            cardIn.setBalance(newBalance);

            rows = cardMapper.updateByPrimaryKey(cardIn);
            if (1 != rows) {
                throw new BizException("转账失败");
            }

            flow = new Flow();
            flow.setUserId(cardIn.getUserId());
            flow.setRemark(FlowTypeEnum.TRANSFER_IN.getV());
            flow.setFlowType(FlowTypeEnum.TRANSFER_IN.getK());
            flow.setCreateTime(new Date());
            flow.setCardId(cardIn.getId());
            flow.setAmount((int)(Double.parseDouble(amount) * 100));

            rows = flowMapper.insert(flow);
            if (1 != rows) {
                throw new BizException("转账失败");
            }

            // 提交事务或者
            sqlSession.commit();

        } catch (Exception e) {
            sqlSession.rollback();
            throw e;
        } finally {
            sqlSession.close();
        }

        return 0;
    }

    @Override
    public List<CardDTO> queryCards(long userId) {

        try (SqlSession sqlSession = DBUtils.getSqlSession()) {
            CardMapper cardMapper = sqlSession.getMapper(CardMapper.class);
            List<Card> cards = cardMapper.listCard(userId);

            List<CardDTO> dtos = new ArrayList<>();
            for (Card card : cards) {
                CardDTO cardDTO = new CardDTO();
                dtos.add(cardDTO);

                cardDTO.setBalance(String.valueOf(card.getBalance()/ 100));
                cardDTO.setCardId(card.getId());
                cardDTO.setCardNum(CardUtil.formatNum(card.getCardNum()));
            }

            return dtos;
        }
    }
}
